#pragma once
#include <atomic>
#include <condition_variable>
#include <functional>
#include <memory>
#include <queue>
#include <thread>
#include <unordered_map>

#include "task.h"
enum class PoolMode { MODE_FIXED, MODE_CACHED };

class Thread {
public:
    using ThreadFunc = std::function<void(int)>;

    Thread(ThreadFunc func);
    ~Thread();

    void start();
    int getId() const {
        return threadId_;
    }

private:
    ThreadFunc func_;
    static int generateId_;
    int threadId_;
};

class ThreadPool {
public:
    ThreadPool();
    ~ThreadPool();

    void setMode(PoolMode mode);
    void setTaskSizeThreshhold(int threshhold);
    void setThreadSizeThreshhold(int threshhold);

    Result submit(std::shared_ptr<Task> task);
    void start(int initThreadSize = std::thread::hardware_concurrency());

    ThreadPool(const ThreadPool&) = delete;
    ThreadPool& operator=(const ThreadPool&) = delete;

private:
    void threadfunc(int threadId);
    bool checkRunningState() const {
        return isPoolRunning_;
    }

private:
    std::unordered_map<int, std::unique_ptr<Thread>> threads_;
    int initThreadSize_;
    int threadSizeThreshhold_;
    std::atomic_int idleThreadSize_;

    std::queue<std::shared_ptr<Task>> tasks_;
    int taskSizeThreshhold_;

    std::mutex mtx_;
    std::condition_variable notEmpty_;
    std::condition_variable notFull_;
    std::condition_variable exitCond_;

    PoolMode mode_;
    std::atomic_bool isPoolRunning_;
};
